#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Math;

#endregion

namespace Weazel.Gezel.Simulator.Reference
{
  /// <summary>
  /// A finite state machine contains a set of state
  /// and foreach state, a set of possible transitions.
  /// The information associated with each transition
  /// (source and target state, optional condition) is
  /// stored in the FsmTransition object which is also
  /// used to determine if the transition should be
  /// taken during simulation.
  /// </summary>
  class FsmTransition
  {
    /// <summary>
    /// Target state of the transition
    /// </summary>
    private readonly Symid targetState;

    /// <summary>
    /// Optional condition associated with
    /// transition
    /// </summary>
    private readonly AbstractSignal condition;

    /// <summary>
    /// Points to the instructions should be
    /// executed when the transition is taken
    /// </summary>
    private readonly int instructionId;

    /// <summary>
    /// Constructs a new transition with the specified
    /// target state and instruction identifier. Optionally,
    /// a signal tree representing a condition to be
    /// evaluated for the fsm to determine if this
    /// transition should be taken during simulation
    /// </summary>
    /// <param name="targetStateId">target state identifier</param>
    /// <param name="condition">condition to evaluate, null iff no condition</param>
    /// <param name="instructionId">instruction identifier</param>
    public FsmTransition(Symid targetStateId, AbstractSignal condition, int instructionId) 
    {
      this.targetState = targetStateId;
      this.condition = condition;
      this.instructionId = instructionId;
    }

    /// <summary>
    /// Called from the finite state machine to 
    /// determine if this particular transition
    /// should be taken in the given state. If
    /// the transition has an associated condition,
    /// it is evaluated to determine if the transition
    /// is eglible for execution. Unconditional 
    /// transitions are always eglible for execution
    /// </summary>
    /// <param name="generation">simulation cycle</param>
    /// <param name="target">target state identifier</param>
    /// <param name="instruction">instruction id</param>
    /// <returns>true iff the the transition should be taken</returns>
    public bool ShouldTakeTransition(long generation, out Symid target, out int instruction)
    {
      target = targetState;
      instruction = instructionId;
      // if transition has condition, use it to determine eglibility
      if (condition != null)
      {
        if (!condition.Evaluate(null, generation).Equals(Integer.Zero))
          return true;
        else
          return false;
      }
      else
        // always eglible for execution
        return true;
    }
  }
}
